﻿using AutoMapper;
using MathNet.Numerics.Distributions;
using NPOI.HSSF.Record.Chart;
using Quartz;
using Quartz.Util;
using Serilog;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Security.Policy;
using System.Text;
using System.Threading.Tasks;
using WCS_Core_Configuration;
using WCS_Entity.Dto.AutoEquipmentDto;
using WCS_Quartz_Task;
using WCS_Quartz_Task._631;
using WCS_Service.DomianService.Interface;
using WCS_Service.DomianService.Models;
using WCS_Service.Enums;
using WCS_Service.Interface;
using WCS_Service.Models.SerialNetModel;
using WCS_Service.Services;
using WCS_Utility.ConstString;
using WCS_Utility.Extensions;

namespace WCS_Service.DomianService.AutoEquipmentDomain
{
    /// <summary>
    /// AGV设备管理服务
    /// </summary>
    public class AGVDomianService : AutoEquipmentDomainService<AGVCustomInfoModel>, IAGVDomainService
    {
        #region 属性
        private List<RollerAbnormalModel> rollerAbnormalModels;
        #endregion
        IMapper _mapper;
        private ConcurrentDictionary<string, AgvWaitInfoModel> waitAgvs = new();
        private ConcurrentDictionary<string, ManageAgvModel> manageAgvInfos = new();
        private readonly IQuartzJobProcess _quartzJobProcess;
        public event Func<Task> agvArriveCharge;
        public event Func<string,string, Task> agvOverTimeChange;
        public event Func<string, string, Task> agvContinueChange;
        public event Func<ManageAgvModel, Task> agvAbnormalChange;
        private int maxTime = 60;

        public AGVDomianService(IAutoEquipmentService autoEquipmentService, 
            IComControl comControl, IMapper mapper, IQuartzJobProcess quartzJobProcess) : base(autoEquipmentService, comControl, mapper)
        {
            _mapper = mapper;
            _quartzJobProcess = quartzJobProcess;
            InitAgvInfo();
        }

        private async void InitAgvInfo()
        {
            if (_autoEquipmentService is null)
            {
                return;
            }
            var agvInfos = await _autoEquipmentService.QueryAutoEquipmentBaseTypeAsync(ConstStringData.AGV_eq);
            if (agvInfos is null || !agvInfos.Any())
            {
                return;
            }
            List<Task> agvAdd = new();
            foreach (var item in agvInfos)
            {
                agvAdd.Add(RecordAgvAsync(item));
            }
            await Task.WhenAll(agvAdd);

            var time = AppSettingsConstVars.OpticalMaxTime;
            if (string.IsNullOrEmpty(time) || !int.TryParse(time, out maxTime))
            {
                Log.Error($"未设置光通讯最长间隔时间!");
                return;
            }
            await RcsOverTimeJob();
            await AGVWaitTAskJob();


            //滚筒异常配置读取
            var abnormalInfos = AppSettingsConstVars.ReadRoadWayInfos<RollerAbnormalModel>(ConstStringData.RollerAbnormalKey);
            if (abnormalInfos is null)
            {
                Log.Error("滚筒异常信息配置未获取到!");
                return;
            }
            rollerAbnormalModels = abnormalInfos;
        }

        #region 定时任务
        private async Task RcsOverTimeJob()
        {
            var jobDetail = JobBuilder.Create<AgvOvertimeJob>().WithIdentity(ConstStringData.AgvOverTimeCheck,
                   ConstStringData.AgvOverTimeCheck).Build();
            jobDetail.JobDataMap.Put("agvOverTime", AgvOvertimeCheck);
            var trigger = TriggerBuilder.Create()
                                        .WithSimpleSchedule(m =>
                                        {
                                            m.WithIntervalInSeconds(20).RepeatForever();
                                        })
                                        .Build();

            //添加超时间检查
            await _quartzJobProcess.AddJobAsync(jobDetail, trigger);
        }

        private async Task AGVWaitTAskJob()
        {
            var jobDetail = JobBuilder.Create<AgvWaitJob>().WithIdentity(ConstStringData.AgvWait,
                   ConstStringData.AgvWait).Build();
            jobDetail.JobDataMap.Put("agvWait", AgvWaitInfos);
            var trigger = TriggerBuilder.Create()
                                        .WithSimpleSchedule(m =>
                                        {
                                            m.WithIntervalInSeconds(5).RepeatForever();
                                        })
                                        .Build();

            //添加超时间检查
            await _quartzJobProcess.AddJobAsync(jobDetail, trigger);
        }
        #endregion

        #region Public
        /// <summary>
        /// 获取所有AGV数据
        /// </summary>
        /// <returns></returns>
        public async Task<List<ManageAgvModel>> QueryAllAgvInfoBaseAsync()
        {
            return await Task.Run(() => 
            {
                List<ManageAgvModel> result = new List<ManageAgvModel>();
                if (manageAgvInfos is null)
                {
                    return result;
                }
                foreach (var manageAgvInfo in manageAgvInfos)
                {
                    result.Add(manageAgvInfo.Value);
                }
                return result;
            });
        }
        /// <summary>
        /// 添加等待继续执行任务的AGV
        /// </summary>
        /// <param name="agvCode"></param>
        /// <param name="waitType"></param>
        /// <returns></returns>
        public async Task AddWaitAgvAsync(string agvCode, AgvWaitInfoModel waitInfo)
        {
            if (!waitAgvs.ContainsKey(agvCode))
            {
                waitAgvs.AddOrUpdate(agvCode, waitInfo, (key, value) => value);
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="eqCode"></param>
        /// <returns></returns>
        public async Task AgvEqCodeUpdate(string eqCode)
        {
            await Task.Run(() => 
            {
                var agvInfo = manageAgvInfos.FirstOrDefault(m => m.Value.site == eqCode);
                if (agvInfo.Value is null)
                {
                    Log.Error($"和光通信{eqCode}处停靠的AGV不存在");
                    return;
                }
                var newValue = agvInfo.Value;
                newValue.site = "";
                manageAgvInfos.AddOrUpdate(agvInfo.Key, newValue, (key, value) => value);
            });
        }
        /// <summary>
        /// 根据光通信设备查找AGV
        /// </summary>
        /// <param name="eqCode"></param>
        /// <returns></returns>
        public async Task<ManageAgvModel> QueryAgvInfoBaseEqCodeAsync(string eqCode)
        {
            return await Task.Run(() => 
            {
                var agvInfo = manageAgvInfos.FirstOrDefault(m => m.Value.site == eqCode);
                if (agvInfo.Value is null)
                {
                    return null;
                }
                return agvInfo.Value;
            });
        }

        /// <summary>
        /// 读取到的AGV信息-更新AGV数据
        /// </summary>
        /// <returns></returns>
        public async Task UpdateAgvInfoAsync(List<AgvInfoModel> infos,string eqCode)
        { 
            List<Task> addAgv = new();

            foreach (var item in infos) 
            {
                addAgv.Add(UpdateAgvStatesAsync(item, eqCode));
            }
            await Task.WhenAll(addAgv);
        }
        /// <summary>
        /// 更新AGV的外设数据
        /// </summary>
        /// <param name="type"></param>
        /// <param name="para"></param>
        /// <returns></returns>
        public async Task UpdateAgvPeripheralAsync(string type, object para)
        {
            switch (type)
            {
                case ConstStringData.Roller_Peripheral:
                    await AddRollerInfoAsync(para);
                    break;
            }
        }
        #endregion

        #region private
        //添加滚筒数据
        private async Task AddRollerInfoAsync(object para)
        {
            var data = para as RollerReadInfoModel;
            if (data is null)
            {
                Log.Error($"接收的滚筒数据转换失败{para}");
                return;
            }
            if (manageAgvInfos.ContainsKey(data.agvCode))
            {
                manageAgvInfos.TryGetValue(data.agvCode,out ManageAgvModel agvInfo);
                if (agvInfo is not null)
                {
                    agvInfo.rollerInfo = data;
                    agvInfo.updateTime = DateTime.Now;
                    if (!string.IsNullOrEmpty(data.rollerDownWarn) || !string.IsNullOrEmpty(data.rollerUpWarn))
                    {
                        agvInfo.status = AgvStates.RollerAbnormal;
                        if (rollerAbnormalModels is not null)
                        {
                            agvInfo.abnormalMsg = $"上层滚筒异常{GetRollerAbnormalCommon(data.rollerUpWarn)}|下层滚筒异常{GetRollerAbnormalCommon(data.rollerDownWarn)}";
                        }
                        else
                        {
                            agvInfo.abnormalMsg = $"滚筒异常";
                        }
                        Log.Information($"AGV滚筒状态异常{agvInfo.abnormalMsg}");
                        //触发agv异常事件
                        agvAbnormalChange?.Invoke(agvInfo);
                    }
                    manageAgvInfos.AddOrUpdate(data.agvCode, agvInfo, (key, value) => value);
                }
            }
        }

        private string GetRollerAbnormalCommon(string warn)
        {
            var info = rollerAbnormalModels.Where(r => r.Code == warn).FirstOrDefault();
            return info?.Common;
        }

        /// <summary>
        /// 判断等待中AGV是否满足离开条件
        /// </summary>
        /// <returns></returns>
        private async Task AgvWaitInfos()
        {
            if (waitAgvs.Any())
            {
                List<Task<string>> addRemove = new List<Task<string>>();
                foreach (var agvInfo in waitAgvs)
                {
                    addRemove.Add(AgvStopWaitCheckerAsync(agvInfo.Value));
                }

                await Task.WhenAll(addRemove);

                var leaveAgvs = addRemove.Where(a => a.Result != ConstStringData.Null)?.Select(a => a.Result)?.ToList();
                if (leaveAgvs is not null && leaveAgvs.Any())
                {
                    leaveAgvs.ForEach(a => 
                    {
                        if (waitAgvs.TryGetValue(a, out AgvWaitInfoModel info))
                        {
                            KeyValuePair<string, AgvWaitInfoModel> removeValue =
              new KeyValuePair<string, AgvWaitInfoModel>(a, info);
                            if (waitAgvs.TryRemove(removeValue))
                            {
                                agvContinueChange?.Invoke(info.opticalId,info.taskCode);
                            }
                        }
                    });
                }
            }
        }
        /// <summary>
        /// agv是否停止等待判断
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        private async Task<string> AgvStopWaitCheckerAsync(AgvWaitInfoModel model)
        {
            return await Task.Run(() => 
            {
                string result = ConstStringData.Null;
                if (manageAgvInfos.TryGetValue(model.agvCode, out ManageAgvModel agvInfo) && agvInfo is not null)
                {
                    switch (model.type)
                    {
                        case AgvWaitState.UpRollerMatNull:
                            result = agvInfo.rollerInfo.materialUpState == MaterialState.Null ? agvInfo.agvCode : ConstStringData.Null;
                            break;
                        case AgvWaitState.UpRollerMatHave:
                            result = agvInfo.rollerInfo.materialUpState == MaterialState.Have ? agvInfo.agvCode : ConstStringData.Null;
                            break;
                        case AgvWaitState.DownRollerMatNull:
                            result = agvInfo.rollerInfo.materialDownState == MaterialState.Null ? agvInfo.agvCode : ConstStringData.Null;
                            break;
                        case AgvWaitState.DownRollerMatHave:
                            result = agvInfo.rollerInfo.materialDownState == MaterialState.Have ? agvInfo.agvCode : ConstStringData.Null;
                            break;
                    }
                }
                return result;
            });
            
        }
        /// <summary>
        /// AGV两个光通讯点上报状态间隔时间过长
        /// </summary>
        /// <returns></returns>
        private async Task AgvOvertimeCheck()
        {
            await Task.Run(() => 
            {
                foreach (var item in manageAgvInfos)
                {
                    //AGV状态更新超过最大时间
                    if ((DateTime.Now - item.Value.updateTime).TotalMinutes > maxTime)
                    {
                        item.Value.stateAbnormal = true;
                        agvOverTimeChange?.Invoke(item.Value.agvCode, item.Value.site);
                    }
                }
            });
           
        }
        private async Task UpdateAgvStatesAsync(AgvInfoModel info,string site)
        {
            ManageAgvModel manageAgvModel = new ManageAgvModel();
            manageAgvModel.agvCode = info.robotCode;
            manageAgvModel.battery = info.battery;
            manageAgvModel.stop = info.stop;
            manageAgvModel.podCode = info.podCode;
            manageAgvModel.status = AgvStateCheck(info.status, out bool stateAbnormal, out string abnormalMsg);
            await ChargeStateProcess(manageAgvModel.status);
            manageAgvModel.stateAbnormal = stateAbnormal;
            manageAgvModel.abnormalMsg = abnormalMsg;
            manageAgvModel.site = site;
            manageAgvModel.path = info.path;
            if (stateAbnormal)
            {
                Log.Information($"AGV状态异常{manageAgvModel.status}|{abnormalMsg}");
                //触发agv异常事件
                agvAbnormalChange?.Invoke(manageAgvModel);
            }

            if (int.TryParse(info.battery, out int value1) && int.TryParse(AppSettingsConstVars.LowWorkBattery, out int value2))
            {
                if (value1 < value2)
                {
                    manageAgvModel.isLowBattery = true;
                }
            }
            else
            {
                Log.Error($"电量数值转换失败!");
            }
            manageAgvInfos.AddOrUpdate(info.robotCode, manageAgvModel, (key, value) => value);
        }

        private async Task ChargeStateProcess(AgvStates agvStates)
        {
            await Task.Run(() => 
            {
                if (agvStates == AgvStates.Chargingstatus)
                {
                    agvArriveCharge?.Invoke();
                }
            });
        }

        private async Task RecordAgvAsync(AutoEquipmentDto item)
        {
            await AddConEquipmentAsync(item.id, item);
        }

        private AgvStates AgvStateCheck(string state,out bool stateAbnormal,out string abnormalMsg)
        {
            var info = state.StringToEnum<AgvStates>();
            stateAbnormal = false;
            abnormalMsg = "";
            switch (info)
            {
                //任务完成
                case AgvStates.Taskcompleted:
                    stateAbnormal = false;
                    break;
                //任务执行中
                case AgvStates.Executingtask:
                    stateAbnormal = false;
                    break;
                //任务异常
                case AgvStates.Abnormaltask:
                    stateAbnormal = true;
                    abnormalMsg = "任务异常";
                    break;
                //任务空闲
                case AgvStates.Idletask:
                    stateAbnormal = false;
                    break;
                //机器人暂停
                case AgvStates.Robotstopped:
                    stateAbnormal = false;
                    break;
                //举升货架状态
                case AgvStates.Liftingshelfstatus:
                    stateAbnormal = false;
                    break;
                //充电状态
                case AgvStates.Chargingstatus:
                    stateAbnormal = false;
                    break;
                //弧线行走状态
                case AgvStates.Batteryarcinginprogress:
                    stateAbnormal = false;
                    break;
                //充满维护
                case AgvStates.Fullycharged:
                    stateAbnormal = false;
                    break;
                //背货未识别
                case AgvStates.Carrieditemnotrecognized:
                    stateAbnormal = true;
                    abnormalMsg = "背货未识别";
                    break;
                //货架偏角过大
                case AgvStates.Excessiveshelfangledivergence:
                    stateAbnormal = true;
                    abnormalMsg = "货架偏角过大";
                    break;
                //运动库异常
                case AgvStates.Motionlibraryexception:
                    stateAbnormal = true;
                    abnormalMsg = "运动库异常";
                    break;
                //货码无法识别
                case AgvStates.Unabletorecogniseproductcode:
                    stateAbnormal = true;
                    abnormalMsg = "货码无法识别";
                    break;
                //货码不匹配
                case AgvStates.Productcodemismatch:
                    stateAbnormal = true;
                    abnormalMsg = "货码不匹配";
                    break;
                //举升异常
                case AgvStates.Liftabnormal:
                    stateAbnormal = true;
                    abnormalMsg = "举升异常";
                    break;
                //充电桩异常
                case AgvStates.Chargingpostabnormal:
                    stateAbnormal = true;
                    abnormalMsg = "充电桩异常";
                    break;
                //充电无增加
                case AgvStates.Noincreaseincurrent:
                    stateAbnormal = true;
                    abnormalMsg = "充电无增加";
                    break;
                //充电角度错误
                case AgvStates.Angleerrorinchargingdirective:
                    stateAbnormal = true;
                    abnormalMsg = "充电角度错误";
                    break;
                //平台下发指令错误
                case AgvStates.Platformdecentralisationdirectiveerror:
                    stateAbnormal = true;
                    abnormalMsg = "平台下发指令错误";
                    break;
                //外力下放
                case AgvStates.Externalforce:
                    stateAbnormal = true;
                    abnormalMsg = "外力下放";
                    break;
                //货架位置偏移
                case AgvStates.Misalignedshelf:
                    stateAbnormal = true;
                    abnormalMsg = "货架位置偏移";
                    break;
                //小车不在锁定区
                case AgvStates.Trolleynotindesignatedzone:
                    stateAbnormal = true;
                    abnormalMsg = "小车不在锁定区";
                    break;
                //下放重试失败
                case AgvStates.Decentralisationfailed:
                    stateAbnormal = true;
                    abnormalMsg = "下放重试失败";
                    break;
                //货架摆歪
                case AgvStates.Unevenshelf:
                    stateAbnormal = true;
                    abnormalMsg = "货架摆歪";
                    break;
                //举升电池电量低
                case AgvStates.Liftbatterycurrenttoolow:
                    stateAbnormal = true;
                    abnormalMsg = "举升电池电量低";
                    break;
                //后退角度偏大
                case AgvStates.Widereversingangle:
                    stateAbnormal = true;
                    abnormalMsg = "后退角度偏大";
                    break;
                //未背负货架举升
                case AgvStates.Norackdetected:
                    stateAbnormal = true;
                    abnormalMsg = "未背负货架举升";
                    break;
                //区域锁定失败
                case AgvStates.Failedtolockzone:
                    stateAbnormal = true;
                    abnormalMsg = "区域锁定失败";
                    break;
                //旋转申失败
                case AgvStates.Rotationrequesttemporarilyfailed:
                    stateAbnormal = true;
                    abnormalMsg = "旋转申失败";
                    break;
                //地图切换点地码未识别
                case AgvStates.Unablerecognisecoordinatesswitchmaps:
                    stateAbnormal = true;
                    abnormalMsg = "地图切换点地码未识别";
                    break;
            }
            return info;
        }
        #endregion
    }
}
